#include<fcntl.h>
#include <string.h>
#include<unistd.h>
#include<termios.h>
#include <common.h>
#include <command.h>
#include <sys/time.h>
#include <time.h>
#include <environment.h>
#include <search.h>
#include <errno.h>
#include <linux/stddef.h>
#include <asm/byteorder.h>
#include "common.h"


#define NDEBUG
/* supported commands including no parameters commands */
#define CMD_SUCCESS					 0		
#define CMD_FAILED					-1		
#define DEVICE_ERROR_PARAMTER		-2      
#define 	CMD_VER   				20
#define		CMD_SETTIME				21
#define 	CMD_READTIME			22
#define 	CMD_LCD					33
#define 	CMD_POWER				112
#define 	CMD_DOOR				110
#define 	CMD_TTYS				156
#define 	CMD_DOOR_SENSOR			223
#define 	CMD_HID_WG				243

/*
 * MCU packet protocol details
 *--------------------------------------------------------------
 *|prefix(2B)|cmd(1B)|~cmd(1B)|.................|checksum(1B)|
 *--------------------------------------------------------------
*/
#define MCU_PACKET_PREFIX_SIZE 		2 
#define MCU_PACKET_CMD_SIZE   		2 /*cmd and ~cmd*/
#define MCU_PACKET_CHECKSUM_SIZE 	1
#define MCUBOARD_COMMAND_DSIZ		17
#define MCU_PACKET_TOTAL_SIZE (MCUBOARD_COMMAND_DSIZ+MCU_PACKET_PREFIX_SIZE+MCU_PACKET_CMD_SIZE+MCU_PACKET_CHECKSUM_SIZE)
#define MCUBOARD_COMMAND_BUFSIZ		64
#define MCU_PACKET_PREFIX 			0x53

static int generate_mcu_packet(unsigned char* packetbuf,unsigned char cmd, void *payload, int payload_length)
{
	int debugging=getenv_yesno("debugging");
	int i;
	unsigned char sum = 0;
	unsigned char *pos = packetbuf;
	
	if (payload_length > MCUBOARD_COMMAND_DSIZ)
		return DEVICE_ERROR_PARAMTER;

	//memset(command, 0x00, sizeof(command));
	*pos++ = MCU_PACKET_PREFIX;
	*pos++ = MCU_PACKET_PREFIX;
	*pos++ = cmd;
	*pos++ = (0xff - cmd);
	if (payload != NULL&&payload_length) {
		memcpy(pos, payload, payload_length);
//		pos += payload_length;
	}
	//fill total length and checksum
	if(MCUBOARD_COMMAND_DSIZ-payload_length) {
		memset(pos+payload_length, 0, MCUBOARD_COMMAND_DSIZ-payload_length);
	}
	//calculate checksum
	for (i = 0; i < MCUBOARD_COMMAND_DSIZ; i++) {
		sum += *(pos + i);
	}
	pos += MCUBOARD_COMMAND_DSIZ;
//	pos += (MCUBOARD_COMMAND_DSIZ-payload_length);
	*pos++ = sum;
	if(debugging){
		dumpbuffer("generated mcu packet",(const char*)packetbuf,MCU_PACKET_TOTAL_SIZE);
	}

	return 0;
}

static int serial_select(int fd, int timeout)
{
	fd_set readfds;
	struct timeval tv;

	tv.tv_sec = timeout / 1000;
	tv.tv_usec = (timeout % 1000) * 1000;
	
	FD_ZERO(&readfds);
	FD_SET(fd, &readfds);

	return select(fd + 1, &readfds, NULL, NULL, &tv);
}


/*setting uart*/
static  int set_uart(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if (tcgetattr( fd,&oldtio) != 0) { 
		perror("SetupSerial 1");
		return -1;
    }
    
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD; 
    newtio.c_cflag &= ~CSIZE; 

    switch( nBits ) {
	    case 7:
	        newtio.c_cflag |= CS7;
	        break;
	    case 8:
	        newtio.c_cflag |= CS8;
	        break;
    }

    switch( nEvent ) {
	    case 'O':                    
	        newtio.c_cflag |= PARENB;
	        newtio.c_cflag |= PARODD;
	        newtio.c_iflag |= (INPCK | ISTRIP);
	        break;
	    case 'E':                      
	        newtio.c_iflag |= (INPCK | ISTRIP);
	        newtio.c_cflag |= PARENB;
	        newtio.c_cflag &= ~PARODD;
	        break;
	    case 'N':                    
	        newtio.c_cflag &= ~PARENB;
	        break;
    }

	switch( nSpeed ) {
	    case 2400:
	        cfsetispeed(&newtio, B2400);
	        cfsetospeed(&newtio, B2400);
	        break;
	    case 4800:
	        cfsetispeed(&newtio, B4800);
	        cfsetospeed(&newtio, B4800);
	        break;
	    case 9600:
	        cfsetispeed(&newtio, B9600);
	        cfsetospeed(&newtio, B9600);
	        break;
	    case 115200:
	        cfsetispeed(&newtio, B115200);
	        cfsetospeed(&newtio, B115200);
	        break;
	    default:
	        cfsetispeed(&newtio, B9600);
	        cfsetospeed(&newtio, B9600);
	        break;
    }
    
    if( nStop == 1 ) {
        newtio.c_cflag &=  ~CSTOPB;
    }
    else if ( nStop == 2 ) {
        newtio.c_cflag |=  CSTOPB;
    }
    
    newtio.c_cc[VTIME]  = 3;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);
    
    if((tcsetattr(fd,TCSANOW,&newtio)) != 0) {
        perror("com set error");
        return -1;
    }
    
  //  printf("Communication ok !\n");
    return 0;
}

/*open uart*/
static int open_uart(char *tty,int baudrate,int databits,int parity,int stopbits)
{
	int fd =open(tty,O_RDWR|O_NOCTTY/*|O_NDELAY*/);
	if(fd<0) {
		return fd;
	}

	if(!isatty(STDIN_FILENO))
		printf("stabdard input is not a terimal device\n");

	if(set_uart(fd,baudrate,databits,parity,stopbits)) {
		perror("set_uart is error");
		return -1;
	}	
	
	return fd;
}

static int close_uart(int fd)
{
	if(fd>0) close(fd);
	return 0;
}


static int uart_send(int fd,unsigned char *buff,int size)
{
    int len = 0;
	len=write(fd,buff,size);
	return len;
}



/*send mcu cmd to mcu and recv the data*/	
static int mcu_cmd_communicate(int fd,unsigned char *cmdbuf, int cmdlen,unsigned char *recv_buffer,int recv_buflen, int rcv_timeout)
{
	int timeout = rcv_timeout/100;//calculate 100ms count
	int expected=recv_buflen;
	int received=0;
	int left=expected-received;
	int ret=0;

	//send cmd packet to target
	uart_send(fd, cmdbuf,cmdlen);

	//receive response
	while(received!=expected){
		ret = serial_select(fd, 100/*ms*/);
		if(ret<=0){
			 timeout--;
			 if(timeout<=0) break;
			 continue;
		}
		ret = read(fd,recv_buffer+received,left);
		if(ret>0) {
			received+=ret;
			left=expected-received;
		}
	}
	return received;
}

static int mcu_uart_init(void)
{
	int fd;
	//
	//open mcu connect serial 
	//
	char* tty;
	tty = getenvvalue("mcutty");
	if(!tty){
		tty="/dev/ttyS1";
	}
	fd = open_uart(tty,115200,8,'N',1);
	if(fd<0){		
		perror("Can't open serial port");
	}
	return fd;	
}

static int mcu_uart_close(int fd)
{
	return close_uart(fd);
}


static int do_mcu_ver(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	memset(sndbuf,0,sizeof(sndbuf));
	memset(recvbuf,0,sizeof(recvbuf));
	int recvlen;
	int fd = mcu_uart_init();
	if(fd<0){
		printf("can't access uart\n");
	}else{
		//construct my mcu version packet
		generate_mcu_packet(sndbuf,CMD_VER,NULL,0);	
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 70);
		if(recvlen>1){
			dumpbuffer("version",(const char*)recvbuf,recvlen);
			//
			//when send version cmd to mcu,mcu will recv a5 and version,so wo need know a5 is before recv cmd
			//
			if(recvbuf[0]==0x5a){
				printf("version :%d\n",recvbuf[6]);
				}else{
					printf("version :%d\n",recvbuf[5]);
				}
				
			}else{
			printf("timeout to receive version\n");
		}
	}
	return 0;
}

/*
 * Note for rtc time operation:
 * All rtc registers are BCD encoding
*/
#ifndef BCD2BIN
#define BCD2BIN(val) (((val) & 0x0f) + ((val) >> 4) * 10)
#endif

#ifndef BIN2BCD
#define BIN2BCD(val) ((((val) / 10) << 4) + (val) % 10)
#endif


static const unsigned char my_rtc_days_in_month[] = {
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static inline bool my_is_leap_year(unsigned int year)
{
     return (!(year % 4) && (year % 100)) || !(year % 400);
}
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)

/*
 * The number of days in the month.
 */
static int my_rtc_month_days(unsigned int month, unsigned int year)
{
	return my_rtc_days_in_month[month] + (my_is_leap_year(year) && month == 1);
}

/*
 * Does the rtc_time represent a valid date/time?
 */
static int rtc_valid_time(struct tm *tm)
{
	if (tm->tm_year < 70
		|| ((unsigned)tm->tm_mon) >= 12
		|| tm->tm_mday < 1
		|| tm->tm_mday > my_rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
		|| ((unsigned)tm->tm_hour) >= 24
		|| ((unsigned)tm->tm_min) >= 60
		|| ((unsigned)tm->tm_sec) >= 60)
		return -EINVAL;

	return 0;
}

static const char* weekdays[]=
{
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday",
};

static int do_mcu_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int ret=0;
	unsigned char timebuf[7];
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	unsigned char ucyear;
	int recvlen;
	int fd;
	struct tm tm;
	char* dtstr = argv[1]; //YYYYMMDDhhmmss string
	char dtbuf[16];
	char* e;

	fd = mcu_uart_init();if(fd<0) return -1;
	if(argc<2){
		//if open uart success,construct my mcu version packet
		generate_mcu_packet(sndbuf,CMD_READTIME,NULL,0);
		memset(recvbuf,0,sizeof(recvbuf));
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 140);
		if(recvlen>1){
			if(recvbuf[0]!=0xa5){
				dumpbuffer("time:",(const char*)recvbuf,recvlen);
				//
				//data[0]-data[6]:second,minute,hour,day,month,week,year
				//
				printf("%02d-%02d-%02d %02d:%02d:%02d\n",
					BCD2BIN(recvbuf[10]),
					BCD2BIN(recvbuf[8]),
					BCD2BIN(recvbuf[7]),
					BCD2BIN(recvbuf[6]),
					BCD2BIN(recvbuf[5]),
					BCD2BIN(recvbuf[4]));
			}
			else{
				dumpbuffer("time:",(const char*)recvbuf,recvlen);
				printf("%02d-%02d-%02d-%02d:%02d:%02d\n",
					BCD2BIN(recvbuf[11]),
					BCD2BIN(recvbuf[9]),
					BCD2BIN(recvbuf[8]),
					BCD2BIN(recvbuf[7]),
					BCD2BIN(recvbuf[6]),
					BCD2BIN(recvbuf[5]));
			}
		}
		else {
			printf("read time failed\n");
			ret=-1;goto bailout;
		}
	}else{
		memset(timebuf,0,sizeof(timebuf));
		memset(sndbuf,0,sizeof(sndbuf));
		memset(recvbuf,0,sizeof(recvbuf));
		memset((void *) &tm, 0, sizeof(tm));
		//YYYYMMDDhhmmss format
		if(argc==2) {
			if(strlen(dtstr)<14){
				printf("bad YYYYMMDDhhmmss format\n"); ret=-1;goto bailout;
			}
			//fetch YYYY
			memcpy(dtbuf,dtstr,4);
			dtbuf[4]='\0';
			tm.tm_year = simple_strtoul (dtbuf,&e,0)-1900;
			//fetch MM
			memcpy(dtbuf,dtstr+4,2);
			dtbuf[2]='\0';
			if(dtbuf[0]=='0') memmove(&dtbuf[0],&dtbuf[1],2);
			tm.tm_mon = simple_strtoul (dtbuf,&e,0)-1;
			//fetch DD
			memcpy(dtbuf,dtstr+4+2,2);
			dtbuf[2]='\0';
			if(dtbuf[0]=='0') memmove(&dtbuf[0],&dtbuf[1],2);
			tm.tm_mday = simple_strtoul (dtbuf,&e,0);
			//fetch hh
			memcpy(dtbuf,dtstr+4+2+2,2);
			dtbuf[2]='\0';
			if(dtbuf[0]=='0') memmove(&dtbuf[0],&dtbuf[1],2);
			tm.tm_hour = simple_strtoul (dtbuf,&e,0);
			//fetch mm
			memcpy(dtbuf,dtstr+4+2+2+2,2);
			dtbuf[2]='\0';
			if(dtbuf[0]=='0') memmove(&dtbuf[0],&dtbuf[1],2);
			tm.tm_min = simple_strtoul (dtbuf,&e,0);
			//fetch ss
			memcpy(dtbuf,dtstr+4+2+2+2+2,2);
			dtbuf[2]='\0';
			if(dtbuf[0]=='0') memmove(&dtbuf[0],&dtbuf[1],2);
			tm.tm_sec = simple_strtoul (dtbuf,&e,0);
		}else if(argc==3){//YYYY-MM-DD hh:mm:ss
			if((3!=sscanf(argv[1],"%04d-%02d-%02d",&tm.tm_year,&tm.tm_mon,&tm.tm_mday))&&
				(3!=sscanf(argv[1],"%04d%02d%02d",&tm.tm_year,&tm.tm_mon,&tm.tm_mday))){
				printf("bad YYYY-MM-DD or YYYYMMDD format [%s]\n",argv[1]);
			}else if((3!=sscanf(argv[2],"%02d:%02d:%02d",&tm.tm_hour,&tm.tm_min,&tm.tm_sec))&&
				(3!=sscanf(argv[2],"%02d%02d%02d",&tm.tm_hour,&tm.tm_min,&tm.tm_sec))){
				printf("bad hh:mm:ss or hhmmss format [%s]\n",argv[1]);
				ret = -1;goto bailout;
			}
			tm.tm_year-=1900;
			tm.tm_mon-=1;
		}

		//for epoch
		if((tm.tm_year+1900)>=2000)
			ucyear = tm.tm_year+1900-2000;
		else{
			//it seems rtc chip has no support for year before 2000.
			printf("%d year is not supported by rtc, fall back to 2000\n",tm.tm_year+1900);
			tm.tm_year = 2000-1900;
		}

		//just for local weekday
		{
			int d=tm.tm_mday;
			int m=tm.tm_mon + 1;
			int y=tm.tm_year + 1900;
			tm.tm_wday=(d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7;
		}
		//sanity check
		if(rtc_valid_time(&tm)<0){
			printf("invalid time to set\n");ret=-1;goto bailout;
		}
		//
		//** set mcu time data[0]~data[6]:second,minute,hour,day,month,week,year
		//

		printf("time set-> %04d-%02d-%02d %s %02d:%02d:%02d\n",
			(tm.tm_year + 1900),
			(tm.tm_mon + 1),
			tm.tm_mday,
			weekdays[tm.tm_wday],
			tm.tm_hour,
			tm.tm_min,
			tm.tm_sec);

		timebuf[0]=BIN2BCD(tm.tm_sec);
		timebuf[1]=BIN2BCD(tm.tm_min);
		timebuf[2]=BIN2BCD(tm.tm_hour);
		timebuf[3]=BIN2BCD(tm.tm_mday);
		timebuf[4]=BIN2BCD(tm.tm_mon+1);
		timebuf[5]=BIN2BCD(tm.tm_wday);
		//for back comptibility of weekday
		if(timebuf[5]==0) timebuf[5]=7;

		//special year handler
		ucyear = (unsigned char)(tm.tm_year-100);
		timebuf[6]=BIN2BCD(ucyear);

		generate_mcu_packet(sndbuf,CMD_SETTIME,timebuf,sizeof(timebuf));
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 70);
		if(recvlen<0){
			printf("time out,settime failed\n");
			ret=-1;
			goto bailout;
		}
	}

bailout:
	mcu_uart_close(fd);
	return ret;
}


/*********************************************************************
when use some cmd havn't useful recv buf,we can use it only send cmd 
*********************************************************************/
static int do_mcu_public(unsigned char cmd)
{
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	memset(sndbuf,0,sizeof(sndbuf));
	memset(recvbuf,0,sizeof(recvbuf));
	int recvlen;
	int fd = mcu_uart_init();
	if(fd<0){
		printf("can't access uart\n");
	}else{
		//construct my mcu version packet
		generate_mcu_packet(sndbuf,cmd,NULL,0);	
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 1000);
		if(recvlen>1){
			//dumpbuffer("time",recvbuf,recvlen);
			printf("it's support\n");
		}else{
			printf("timeout to receive\n");
		}
		mcu_uart_close(fd);
	}
	return 0;
}




static int do_mcu_lcd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	//read lcd parameter
	return do_mcu_public(CMD_LCD);
}

static int do_mcu_door(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	//Inquire door_sensor input status
	return do_mcu_public(CMD_DOOR);
}

static int do_mcu_power(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	memset(sndbuf,0,sizeof(sndbuf));
	memset(recvbuf,0,sizeof(recvbuf));
	int recvlen=0;
	int statu=-1;
	int fd = mcu_uart_init();
	if(fd<0){
		printf("can't access uart\n");
	}else{
		//Inquire mcu power work 
		generate_mcu_packet(sndbuf,CMD_POWER,NULL,0);	
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 50);
		if(recvlen>1){
			statu=recvbuf[2];
			if(statu!=0){
				printf("It is powered by battery");
			}
			else{
				printf("It is powered by external power");
			}
		}else{
			printf("timeout to receive\n");
		}
		
		mcu_uart_close(fd);
	}
	return 0;
}

static int do_mcu_ttys(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	return do_mcu_public(CMD_TTYS);
}

static int do_mcu_bat(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	memset(sndbuf,0,sizeof(sndbuf));
	memset(recvbuf,0,sizeof(recvbuf));
	int recvlen=0;
	int statu=-1;
	int fd = mcu_uart_init();
	if(fd<0){
		printf("can't access uart\n");
	}else{
		//construct my mcu version packet
		generate_mcu_packet(sndbuf,113,NULL,0);	
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 50);
		if(recvlen>1){
			statu=recvbuf[2];
			if(statu!=0){
				printf("It is powered by a battery");
			}
			else{
				printf("It is powered by external power");
			}
		}else{
			printf("timeout to receive\n");
		}
		
		mcu_uart_close(fd);
	}
	return 0;
}


static unsigned char TABLE[8] =
		{ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
static unsigned char INSIDE_WG_TABLE[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04,
		0x02, 0x01 };

static int mcu_check_data(int dsiz, unsigned char *data)
{
	int i = 0;
	unsigned char  sum = 0;
	unsigned char cmd;
	if(*data++ != 0x53 || *data++ != 0x53){
		printf("packet prefix error\n");		
		return  -1;
	}
	cmd = *data++;
	if((cmd + *data++) !=0xff){
		printf("packet cmd invalid\n");
		return -1;
	}
	for(i = 0; i < dsiz - 5; i++, data++){
		sum += *data;
	}
	if(*data != sum){
		printf("packet checksum mismatch\n");
		return -1;
	}
	return 0;
}


static unsigned char WG26Checkout(unsigned char * p_data) {
	short cnt, i, j;
	unsigned char checkout_bit = 0;
	unsigned char checkout_even_bit = 0;

	for (cnt = 0; cnt < 12; cnt++) { //����ǰʮ��λ1�ĸ���żУ��
		i = cnt / 8;
		j = cnt % 8;
		if (p_data[i] & INSIDE_WG_TABLE[j]) {
			checkout_bit ^= 1;
		}
	}
//	LOGD("checkout_bit=%d\n", checkout_bit);

	for (cnt = 12; cnt < 24; cnt++) { //�����ʮ��λ1�ĸ�����Ч��
		i = cnt / 8;
		j = cnt % 8;
		if (p_data[i] & INSIDE_WG_TABLE[j]) {
			checkout_even_bit ^= 1;
		}
	}
//	LOGD("checkout_even_bit=%d\n", checkout_even_bit);

	if (checkout_even_bit==0x00) {
		p_data[3] |= 0x40;
	}
	if (p_data[2] & 0x01) {
		p_data[3] |= 0x80;
	}
	p_data[2] = p_data[2] >> 1;

	if (p_data[1] & 0x01) {
		p_data[2] |= 0x80;
	}
	p_data[1] = p_data[1] >> 1;

	if (p_data[0] & 0x01) {
		p_data[1] |= 0x80;
	}
	p_data[0] = p_data[0] >> 1;

	if(checkout_bit & 0x01){
		p_data[0] |= 0x80;
	}

	return 1;
}


static void dump_hexbuffer(const char *prefix,const char *data ,int size)
{
#ifndef isprint
#define isprint(c)	(c>='!'&&c<='~')
#endif
//((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
	char* ptr;
	static char digits[2048] = {0};
	int i, j;	
	unsigned char *buf = (unsigned char*)data;
	fprintf(stdout,"%s\n",
			   prefix?prefix:" ");

	
	for (i=0; i<size; i+=16) 
	{
	  ptr = &digits[0];
	  ptr+=sprintf(ptr,"%06x: ",i);
	  for (j=0; j<16; j++) 
		if (i+j < size)
		 ptr+=sprintf(ptr,"%02x ",buf[i+j]);
		else
		 ptr+=sprintf(ptr,"%s","   ");

	  ptr+=sprintf(ptr,"%s","  ");
		
	  for (j=0; j<16; j++) 
		if (i+j < size)			
			ptr+=sprintf(ptr,"%c",isprint(buf[i+j]) ? buf[i+j] : '.');
	  *ptr='\0';
	  fprintf(stdout,"%s\n",digits);
	}
}

static int do_mcu_monitor(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{	

	char mcu_buffer[1024];
	char typevalue[1024];
	int ret,received=0;
	int packet_len;
	int cardnumber = 0;
	unsigned char *pos=NULL;
	int cmd_count=0;
	
	int i;
	int cmd;
	char data[20] = {0};
	int fd = mcu_uart_init();
	if(fd<0){
		printf("can't access uart\n"); return -1;
	}
	
	//receive response
	while(1){
		received=0;
loop_read:
		if ((had_ctrlc())) {
			printf("Ctrl^C interrupted\n");
			break;
		}
		ret = serial_select(fd, 1000/*ms*/);
		
		if(ret<=0){
			 continue;
		}
		ret = read(fd,mcu_buffer+received,1024-received);
		if(ret>0) {
			received+=ret;
		}
		if(received<12) goto loop_read;
		

		//payload ready
		pos = &mcu_buffer[0];

		if(getenv_yesno("mcu_debug")){
			printf("Relay Event IN[%d] Stats[%d]\n",received,cmd_count++);
			dump_hexbuffer("Event Details",pos,received);
		}
		
		//skip packet prefix 
		cmd = *(pos + 2);
		switch(cmd){
			case 0xd7:
			case 0x33:
			case 0xda:
				packet_len = 13;
				break;
			default:
				packet_len = 12;
				break;
		}
		if(*pos == 0xA5 ){
			printf("short reponse 0xA5 reached\n");
			continue;
		}
		if( (mcu_check_data(packet_len, pos)) < 0){
			continue;
		}
	
	if(getenv_yesno("mcu_debug")){		
		printf("Relay Event:%#x [%s]\n",cmd,
			(215==cmd)?"WIEGAND-IN 26bit event @port5v":
			(218==cmd)?"WIEGAND-IN non-26bit event @port5v":
			(50==cmd)?"WIEGAND-IN 26bit event @port12v":
			(51==cmd)?"WIEGAND-IN non-26bit event @port12v":
			(151==cmd)?"AUX":
			(110==cmd)?"AUX":
			(22==cmd)?"RTC":"Unknonw");
	}
	switch(cmd)
	{
		case 215://for 26bit wiegand-in data on wiegand-in port 5v
			memcpy((data + 1), (pos + 4), packet_len-6);
			data[0] = 0x1A;
			unsigned char i, j, h_bit, l_bit;
			int byteLen = data[0] / 8;
			int bitLen = data[0] % 8;
	
			for (i = 1; i < byteLen + 2; i++) {
				unsigned char h = 0x80;
				unsigned char l = 0x01;
				for (j = 0; j < 4; j++) { //switch nibble bytes
					h_bit = data[i] & h;l_bit = data[i] & l;
					if (!h_bit) data[i] |= l; else data[i] &= ~l;
					if (!l_bit) data[i] |= h; else data[i] &= ~h;
					h >>= 1;l <<= 1;
				}
			}
			if (bitLen == 0) {
				data[byteLen + 1] = 0x00;
			} else {
				data[byteLen + 1] &= TABLE[bitLen];
			}

			sprintf(typevalue, "%02x%02x%02x%02x%02x", data[0],*(data + 1), *(data +2), *(data + 3), *(data +4));
			if(getenv_yesno("mcu_debug")){
				printf("WIEGAND-IN [%s]\n", typevalue);
			}
			

 			break;
		case 218://for non-26 bits wiegand format on wiegand-in port 5v
		{
			memcpy(data, (pos + 4), packet_len- 5);
			unsigned char i, j, h_bit, l_bit;
			int byteLen = data[0] / 8;
			int bitLen = data[0] % 8;

			for (i = 1; i < byteLen + 2; i++) {
			    unsigned char h = 0x80;
			    unsigned char l = 0x01;
			    for (j = 0; j < 4; j++) { //switch nibble of each byte 
				    h_bit = data[i] & h;l_bit = data[i] & l;
					if (!h_bit) data[i] |= l; else 	data[i] &= ~l;
					if (!l_bit) data[i] |= h; else 	data[i] &= ~h;
					h >>= 1;
					l <<= 1;
				}
			}
			if (bitLen == 0) data[byteLen + 1] = 0x00;else data[byteLen + 1] &= TABLE[bitLen];

			sprintf(typevalue, "%02x%02x%02x%02x%02x%02x%02x%02x", data[0],*(data + 1), *(data +2), *(data + 3), *(data +4), *(data +5), *(data + 6), *(data +7));
			if(getenv_yesno("mcu_debug")){		
				printf("WIEGAND-IN [%s]\n", typevalue);
			}
		}
		break;	
		case  51: //for non-26 bits wiegand format on wiegand-in port 12V
			sprintf(typevalue, "%02x%02x%02x%02x%02x%02x%02x%02x",*(pos + 4), *(pos + 5), *(pos + 6), *(pos + 7), *(pos +8), *(pos +9), *(pos + 10), *(pos +11));
			if(getenv_yesno("mcu_debug")){		
				printf("WIEGAND-IN [%s]\n", typevalue);
			}
			break;

		case  50:
			memcpy((data+1), (pos + 4), packet_len- 5);
			short temp =*(data+1);
			*(data+1)=*(data+3);
			*(data+3)=temp;
			data[0]=0x1A;
		
			WG26Checkout(data+1);
			sprintf(typevalue, "%02x%02x%02x%02x%02x", data[0], *(data + 1), *(data +2), *(data + 3), *(data +4));
			if(getenv_noyes("mcu_debug")){		
				printf("WIEGAND-IN [%s]\n", typevalue);
			}
		

			break;
		case 110 :
			sprintf(typevalue, "%d", *(pos + 4));
			if(getenv_noyes("mcu_debug")){		
				printf("AUX [%s]\n", typevalue);
			}
			break;
		case 151:
			sprintf(typevalue, "%d", 2);
			printf("AUX [%s]\n", typevalue);
			break;
		case 22:			
			if(mcu_buffer[0]!=0xa5){
				dumpbuffer("time:",(const char*)mcu_buffer,received);
				//
				//data[0]-data[6]:second,minute,hour,day,month,week,year
				//
				printf("%02d-%02d-%02d %02d:%02d:%02d\n",
					BCD2BIN(mcu_buffer[10]),
					BCD2BIN(mcu_buffer[8]),
					BCD2BIN(mcu_buffer[7]),
					BCD2BIN(mcu_buffer[6]),
					BCD2BIN(mcu_buffer[5]),
					BCD2BIN(mcu_buffer[4]));
			}
			else{
				dumpbuffer("time:",(const char*)mcu_buffer,received);
				printf("%02d-%02d-%02d-%02d:%02d:%02d\n",
					BCD2BIN(mcu_buffer[11]),
					BCD2BIN(mcu_buffer[9]),
					BCD2BIN(mcu_buffer[8]),
					BCD2BIN(mcu_buffer[7]),
					BCD2BIN(mcu_buffer[6]),
					BCD2BIN(mcu_buffer[5]));
			}
			break;
		default:
			printf("unrecoginized event [%d][%#x] \n",cmd,cmd);
			break;
		}

	}

	mcu_uart_close(fd);

	return 0;
}
static int do_mcu_hid_wg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int recvlen=0;
	int statu=-1;
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	unsigned char hid[17] = {26, 100>>8, 100&0xff, 1000>>8, 100&0xff};
	int fd = mcu_uart_init();
	
	memset(sndbuf,0,sizeof(sndbuf));
	memset(recvbuf,0,sizeof(recvbuf));
	if(fd<0){
		printf("can't access uart\n");
	}else{
		//
		//set wiegand of machine hid card,data[0]:wiegand bit,data[1,2]:Pulse width,data[3,4]:Pulse interval
		//0<data[0]<=64;
		//
		generate_mcu_packet(sndbuf,CMD_HID_WG,hid,sizeof(hid));
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 50);
		if(recvlen>1){
			statu=recvbuf[2];
			//if recv cmd same,meas set success
			if(statu==0xf3){
				printf("set success");
			}
			else{
				printf("set error");
			}
		}else{
			printf("timeout to receive\n");
		}
	}
	return 0;
}

static int do_mcu_door_sensor(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	unsigned char sndbuf[64];
	unsigned char recvbuf[64];
	memset(sndbuf,0,sizeof(sndbuf));
	memset(recvbuf,0,sizeof(recvbuf));
	int recvlen=0;
	int statu=-1;
	int fd = mcu_uart_init();
	if(fd<0){
		printf("can't access uart\n");
	}else{
		//construct my mcu version packet
		generate_mcu_packet(sndbuf,CMD_DOOR_SENSOR,NULL,0);	
		recvlen = mcu_cmd_communicate(fd, sndbuf, MCU_PACKET_TOTAL_SIZE, recvbuf, sizeof(recvbuf), 50);
		if(recvlen>1){
			statu=recvbuf[2];
			if(statu!=0){
				printf("have door sensor\n");
			}
			else{
				printf("no door sensor\n");
			}
		}else{
			printf("timeout to receive\n");
		}
	}
	return 0;
}


/*
 * New command line interface: "env" command with subcommands
 */
static cmd_tbl_t cmd_mcu_sub[] = {
	U_BOOT_CMD_MKENT(ver, 0, 0, do_mcu_ver, "", ""),
	U_BOOT_CMD_MKENT(lcd, 0, 0, do_mcu_lcd, "", ""),
	U_BOOT_CMD_MKENT(pow, 0, 0, do_mcu_power, "", ""),
	U_BOOT_CMD_MKENT(door, 0, 0, do_mcu_door, "", ""),
	U_BOOT_CMD_MKENT(bat, 0, 0, do_mcu_bat, "", ""),
	U_BOOT_CMD_MKENT(ttys, 0, 0, do_mcu_ttys, "", ""),
	U_BOOT_CMD_MKENT(d_sen, 0, 0, do_mcu_door_sensor, "", ""),
	U_BOOT_CMD_MKENT(hid_wg, 0, 0, do_mcu_hid_wg, "", ""),
	U_BOOT_CMD_MKENT(time, 0, 0, do_mcu_time, "", ""),
	U_BOOT_CMD_MKENT(mon, 0, 0, do_mcu_monitor, "", ""),
	
};

static int do_mcu (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	cmd_tbl_t *cp;

	/* drop initial "env" arg */


	argc--;
	argv++;
	if(argc!=0){
		cp = find_cmd_tbl(argv[0], cmd_mcu_sub, ARRAY_SIZE(cmd_mcu_sub));

		if (cp)
			return cp->cmd(cmdtp, flag, argc, argv);
	}
	cmd_usage(cmdtp);
	return 1;
}


U_BOOT_CMD(
	mcu, CONFIG_SYS_MAXARGS, 1,	do_mcu,
	"mcu related commands,with this we can detect and check mcu features supported",
	"\nver				-access mcu firmware version\n"
	"time [YYYYMMDDhhmmss|YYYYMMDD hhmmss|YYYY-MM-DD hh:mm:ss]	-get/set mcu time\n"
	"lcd				-access mcu lenth,wight\n"
	"pow 				-Check the power supply status\n"
	"door				-Check the disassemble alarm switch state and door sensor signal input status\n"
	"bat				-Battery charge status value,only for iclock 700\n"
	"ttys				-access mcu usb coms\n"
	"d_sen				-access door_sensor\n"
	"hid_wg				-set HID wiegand"
);


